import Link from "next/link"; import { BillingAutoRefresh, BillingRefreshListener } from "@/components/billing-refresh-listener"; import { BillingPageState } from "@/components/billing-page-state"; import { type BillingCredits, type BillingInvoices, type BillingSubscription, PopiartApiError, getBillingCredits, getBillingInvoices, getBillingSubscription, getViewerSession, } from "@/lib/popiart-api"; import { type Locale } from "@/lib/site-content"; export const dynamic = "force-dynamic"; function formatNumber(locale: Locale, value: number) { return new Intl.NumberFormat(locale === "zh" ? "zh-CN" : "en-US").format(value); } function formatError(error: unknown) { if (error instanceof PopiartApiError) { return error.message; } if (error instanceof Error) { return error.message; } return String(error); } export default async function BillingPage({ params, searchParams, }: { params: Promise<{ locale: string }>; searchParams: Promise<{ kind?: string; status?: string; page?: string }>; }) { const { locale } = await params; const { kind, status, page } = await searchParams; const typedLocale = locale as Locale; const isZh = typedLocale === "zh"; const session = await getViewerSession(); const title = isZh ? "账单中心" : "Billing"; const subtitle = isZh ? "查看当前订阅、积分钱包和订单历史。" : "Review your active subscription, point wallets, and order history."; const loginCta = isZh ? "去登录" : "Sign in"; const consoleCta = isZh ? "前往控制台" : "Open console"; const unboundTitle = isZh ? "先绑定网关用户" : "Bind a gateway user first"; const unboundBody = isZh ? "当前 session 还没有绑定网关用户态,先去控制台绑定后才能读取真实账单与订单。" : "This session is not bound to a gateway user yet. Bind it in the console first to read live billing and order data."; const subscriptionTitle = isZh ? "当前订阅" : "Current subscription"; const creditsTitle = isZh ? "积分钱包" : "Point wallets"; const invoicesTitle = isZh ? "订单历史" : "Order history"; const noSubscription = isZh ? "当前没有有效订阅。" : "No active subscription."; const noCredits = isZh ? "当前没有积分钱包记录。" : "No point wallets."; const noOrders = isZh ? "当前没有订单记录。" : "No orders yet."; const kindFilter = kind === "subscription" || kind === "points" ? kind : "all"; const statusFilter = typeof status === "string" && status.trim() ? status.trim() : "all"; const currentPage = Number.isFinite(Number(page)) && Number(page) > 0 ? Number(page) : 1; const pageSize = 8; const kindLabel = isZh ? "类型" : "Kind"; const statusLabel = isZh ? "状态" : "Status"; const allLabel = isZh ? "全部" : "All"; const subscriptionsLabel = isZh ? "订阅订单" : "Subscription orders"; const pointsLabel = isZh ? "积分包订单" : "Point orders"; const prevLabel = isZh ? "上一页" : "Previous"; const nextLabel = isZh ? "下一页" : "Next"; const pageLabel = isZh ? "页码" : "Page"; if (!session) { return (

{title}

{subtitle}

{isZh ? "登录后查看真实账单" : "Sign in to view live billing"}

{loginCta}
); } if (!session.gateway_bound) { return (

{title}

{subtitle}

{unboundTitle}

{unboundBody}

{consoleCta}
); } let subscription: BillingSubscription | null = null; let credits: BillingCredits | null = null; let invoices: BillingInvoices | null = null; const errors: string[] = []; const [subscriptionResult, creditsResult, invoicesResult] = await Promise.allSettled([ getBillingSubscription(), getBillingCredits(), getBillingInvoices(), ]); if (subscriptionResult.status === "fulfilled") { subscription = subscriptionResult.value; } else { errors.push(formatError(subscriptionResult.reason)); } if (creditsResult.status === "fulfilled") { credits = creditsResult.value; } else { errors.push(formatError(creditsResult.reason)); } if (invoicesResult.status === "fulfilled") { invoices = invoicesResult.value; } else { errors.push(formatError(invoicesResult.reason)); } type BillingOrderItem = Record & { __kind: "subscription" | "points" }; const allOrders: BillingOrderItem[] = [ ...((invoices?.subscription_orders?.items || []).map((item) => ({ ...item, __kind: "subscription" as const }))), ...((invoices?.point_orders?.items || []).map((item) => ({ ...item, __kind: "points" as const }))), ]; const filteredOrders = allOrders.filter((item) => { if (kindFilter !== "all" && item.__kind !== kindFilter) { return false; } if (statusFilter !== "all" && String(item.status || "") !== statusFilter) { return false; } return true; }); const totalPages = Math.max(1, Math.ceil(filteredOrders.length / pageSize)); const safePage = Math.min(currentPage, totalPages); const pagedOrders = filteredOrders.slice((safePage - 1) * pageSize, safePage * pageSize); const availableStatuses = Array.from( new Set( allOrders .map((item) => String(item.status || "").trim()) .filter(Boolean), ), ); const hasPendingOrders = allOrders.some((item) => { const currentStatus = String(item.status || "").trim(); return currentStatus !== "" && !["success", "SUCCESS", "TRADE_SUCCESS", "failed", "FAILED", "closed", "CLOSED", "TRADE_CLOSED"].includes(currentStatus); }); function buildBillingHref(nextKind: string, nextStatus: string, nextPage: number) { const query = new URLSearchParams(); if (nextKind !== "all") { query.set("kind", nextKind); } if (nextStatus !== "all") { query.set("status", nextStatus); } if (nextPage > 1) { query.set("page", String(nextPage)); } const serialized = query.toString(); return serialized ? `/${locale}/billing?${serialized}` : `/${locale}/billing`; } return (

{title}

{subtitle}

{errors.length > 0 ? (
{errors.join(" | ")}
) : null}

{subscriptionTitle}

{subscription && subscription.subscriptions.length > 0 ? (
{subscription.subscriptions.map((item, index) => (
{item.subscription?.member_level || "subscription"} {item.subscription?.status || "-"}
{isZh ? "可用积分" : "Available points"} {formatNumber( typedLocale, subscription.subscription_points[String(item.subscription?.id)]?.available_points || 0, )}
))}
) : (

{noSubscription}

)}

{creditsTitle}

{credits && credits.wallets.length > 0 ? (
{isZh ? "当前余额" : "Balance"} {formatNumber(typedLocale, credits.balance)}
{isZh ? "钱包数量" : "Wallet count"} {formatNumber(typedLocale, credits.wallets.length)}
{credits.wallets.map((wallet) => (
{wallet.source_type} {isZh ? "可用积分" : "Available points"}: {formatNumber(typedLocale, wallet.points)}
{isZh ? "总积分" : "Total points"} {formatNumber(typedLocale, wallet.points_total)}
))}
) : (

{noCredits}

)}

{invoicesTitle}

{allOrders.length > 0 ? (
{kindLabel}
{allLabel} {subscriptionsLabel} {pointsLabel}
{statusLabel}
{allLabel} {availableStatuses.map((itemStatus) => ( {itemStatus} ))}
{pagedOrders.map((item, index) => (
{String(item.plan_title || item.package_name || item.trade_no || "order")} {String(item.status || "-")}
{String(item.money || "-")} {String(item.currency || "")} {String(item.payment_method || "-")}
{isZh ? "交易号" : "Trade no"} {String(item.trade_no || "-")}
{isZh ? "退款状态" : "Refund status"} {String(item.refund_status || "-")}
{isZh ? "完成时间" : "Completed at"} {String(item.complete_time || "-")}
{item.__kind === "subscription" ? (isZh ? "订阅 ID" : "Subscription ID") : (isZh ? "到账积分" : "Delivered points")} {String(item.__kind === "subscription" ? item.subscription_id : item.points_amount || "-")}
))}
{prevLabel} {pageLabel}: {safePage} / {totalPages} = totalPages} className={`button button-light button-small ${safePage >= totalPages ? "button-disabled" : ""}`} href={buildBillingHref(kindFilter, statusFilter, Math.min(totalPages, safePage + 1))} > {nextLabel}
) : (

{noOrders}

)}
); }